package com.wiki.gds.base.web.controller.config.feign;

import feign.MethodMetadata;
import feign.Util;
import org.springframework.cloud.openfeign.AnnotatedParameterProcessor;
import org.springframework.cloud.openfeign.support.SpringMvcContract;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;


//MySpringMvcContract  配置 postMapping 自动匹配方法名
public class MySpringMvcContract extends SpringMvcContract {
    private ResourceLoader resourceLoader;

    public MySpringMvcContract(List<AnnotatedParameterProcessor> parameterProcessors, ConversionService feignConversionService) {
    }

    @Override
    protected void processAnnotationOnClass(MethodMetadata data, Class<?> clz) {
        if (clz.getInterfaces().length == 0) {
            RequestMapping classAnnotation = (RequestMapping) AnnotatedElementUtils.findMergedAnnotation(clz, RequestMapping.class);
            if (classAnnotation != null && classAnnotation.value().length > 0) {
                String pathValue = Util.emptyToNull(classAnnotation.value()[0]);
                pathValue = this.resolve(pathValue);
                if (!pathValue.startsWith("/")) {
                    pathValue = "/" + pathValue;
                }

                data.template().insert(0, pathValue);
            }
            else {
                
            }
        }
    }

    private String resolve(String value) {
        return StringUtils.hasText(value) && this.resourceLoader instanceof ConfigurableApplicationContext ? ((ConfigurableApplicationContext)this.resourceLoader).getEnvironment().resolvePlaceholders(value) : value;
    }

    @Override
    protected void processAnnotationOnMethod(MethodMetadata data, Annotation methodAnnotation, Method method) {
        if (RequestMapping.class.isInstance(methodAnnotation) || methodAnnotation.annotationType().isAnnotationPresent(RequestMapping.class)) {
            RequestMapping methodMapping = (RequestMapping)AnnotatedElementUtils.findMergedAnnotation(method, RequestMapping.class);
            RequestMethod[] methods = methodMapping.method();
            if (methods.length == 0) {
                methods = new RequestMethod[]{RequestMethod.GET};
            }

            this.checkOne(method, methods, "method");
            data.template().method(methods[0].name());
            this.checkAtMostOne(method, methodMapping.value(), "value");
            String   pathValue=null;
            if (methodMapping.value().length > 0) {
                 pathValue = Util.emptyToNull(methodMapping.value()[0]);
            }
            else {
                pathValue=method.getName();
            }
                if (pathValue != null) {
                    pathValue = this.resolve(pathValue);
                    if (!pathValue.startsWith("/") && !data.template().toString().endsWith("/")) {
                        pathValue = "/" + pathValue;
                    }

                    data.template().append(pathValue);
                }



            this.parseProduces(data, method, methodMapping);
            this.parseConsumes(data, method, methodMapping);
            this.parseHeaders(data, method, methodMapping);
            data.indexToExpander(new LinkedHashMap());
        }
    }
    private void checkOne(Method method, Object[] values, String fieldName) {
        Util.checkState(values != null && values.length == 1, "Method %s can only contain 1 %s field. Found: %s", new Object[]{method.getName(), fieldName, values == null ? null : Arrays.asList(values)});
    }

    private void checkAtMostOne(Method method, Object[] values, String fieldName) {
        Util.checkState(values != null && (values.length == 0 || values.length == 1), "Method %s can only contain at most 1 %s field. Found: %s", new Object[]{method.getName(), fieldName, values == null ? null : Arrays.asList(values)});
    }

    private void parseProduces(MethodMetadata md, Method method, RequestMapping annotation) {
        String[] serverProduces = annotation.produces();
        String clientAccepts = serverProduces.length == 0 ? null : Util.emptyToNull(serverProduces[0]);
        if (clientAccepts != null) {
            md.template().header("Accept", new String[]{clientAccepts});
        }

    }

    private void parseConsumes(MethodMetadata md, Method method, RequestMapping annotation) {
        String[] serverConsumes = annotation.consumes();
        String clientProduces = serverConsumes.length == 0 ? null : Util.emptyToNull(serverConsumes[0]);
        if (clientProduces != null) {
            md.template().header("Content-Type", new String[]{clientProduces});
        }

    }

    private void parseHeaders(MethodMetadata md, Method method, RequestMapping annotation) {
        if (annotation.headers() != null && annotation.headers().length > 0) {
            String[] var4 = annotation.headers();
            int var5 = var4.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                String header = var4[var6];
                int index = header.indexOf(61);
                if (!header.contains("!=") && index >= 0) {
                    md.template().header(this.resolve(header.substring(0, index)), new String[]{this.resolve(header.substring(index + 1).trim())});
                }
            }
        }

    }
}
